home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / userdel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-26  |  9.7 KB  |  492 lines

  1. /*
  2.  * Copyright 1991, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Permission is granted to copy and create derivative works for any
  6.  * non-commercial purpose, provided this copyright notice is preserved
  7.  * in all copies of source code, or included in human readable form
  8.  * and conspicuously displayed on all copies of object code or
  9.  * distribution media.
  10.  */
  11.  
  12. #ifndef lint
  13. static    char    sccsid[] = "@(#)userdel.c    3.9    14:38:36    10/27/91";
  14. #endif
  15.  
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <stdio.h>
  19. #include <errno.h>
  20. #include "pwd.h"
  21. #include <grp.h>
  22. #include <ctype.h>
  23. #include <fcntl.h>
  24. #include <time.h>
  25.  
  26. #ifdef    BSD
  27. #include <strings.h>
  28. #else
  29. #include <string.h>
  30. #endif
  31.  
  32. #include "config.h"
  33. #include "shadow.h"
  34.  
  35. #ifdef    USE_SYSLOG
  36. #include <syslog.h>
  37.  
  38. #ifndef    LOG_WARN
  39. #define    LOG_WARN LOG_WARNING
  40. #endif
  41. #endif
  42.  
  43. gid_t    default_group;
  44. char    default_home[BUFSIZ];
  45. char    default_shell[BUFSIZ];
  46. long    default_inactive;
  47. long    default_expire;
  48. char    default_file[] = "/etc/default/useradd";
  49.  
  50. #ifndef    NGROUPS_MAX
  51. #define    NGROUPS_MAX    64
  52. #endif
  53.  
  54. char    user_name[BUFSIZ];
  55. uid_t    user_id;
  56. gid_t    user_group;
  57. char    user_comment[BUFSIZ];
  58. char    user_home[BUFSIZ];
  59. char    user_shell[BUFSIZ];
  60. int    user_ngroups;
  61. int    user_expire;
  62. gid_t    user_groups[NGROUPS_MAX];
  63.  
  64. char    *Prog;
  65. int    rflg;
  66.  
  67. #ifdef    NDBM
  68. extern    int    pw_dbm_mode;
  69. extern    int    sp_dbm_mode;
  70. extern    int    gr_dbm_mode;
  71. #ifdef    SHADOWGRP
  72. extern    int    sg_dbm_mode;
  73. #endif
  74. #endif
  75. extern    struct    group    *getgrnam();
  76. extern    struct    group    *getgrgid();
  77. extern    struct    group    *gr_next();
  78. extern    struct    passwd    *getpwnam();
  79. extern    struct    passwd    *pw_next();
  80.  
  81. #ifdef    SHADOWGRP
  82. extern    int    sgr_lock();
  83. extern    int    sgr_unlock();
  84. extern    int    sgr_open();
  85. extern    int    sgr_close();
  86. extern    struct    sgrp    *sgr_next();
  87. #endif
  88.  
  89. extern    char    *malloc();
  90.  
  91. /*
  92.  * del_list - delete a member from a list of group members
  93.  *
  94.  *    the array of member names is searched for the old member
  95.  *    name, and if present it is deleted from a freshly allocated
  96.  *    list of users.
  97.  */
  98.  
  99. char **
  100. del_list (list, member)
  101. char    **list;
  102. char    *member;
  103. {
  104.     int    i, j;
  105.     char    **tmp;
  106.  
  107.     /*
  108.      * Scan the list for the new name.  Return the original list
  109.      * pointer if it is present.
  110.      */
  111.  
  112.     for (i = j = 0;list[i] != (char *) 0;i++)
  113.         if (strcmp (list[i], member))
  114.             j++;
  115.  
  116.     if (j == i)
  117.         return list;
  118.  
  119.     /*
  120.      * Allocate a new list pointer large enough to hold all the
  121.      * old entries, and the new entries as well.
  122.      */
  123.  
  124.     if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
  125.         return 0;
  126.  
  127.     /*
  128.      * Copy the original list to the new list, then append the
  129.      * new member and NULL terminate the result.  This new list
  130.      * is returned to the invoker.
  131.      */
  132.  
  133.     for (i = j = 0;list[i] != (char *) 0;i++)
  134.         if (strcmp (list[i], member))
  135.             tmp[j++] = list[i];
  136.  
  137.     tmp[j] = (char *) 0;
  138.  
  139.     return tmp;
  140. }
  141.  
  142. /*
  143.  * usage - display usage message and exit
  144.  */
  145.  
  146. usage ()
  147. {
  148.     fprintf (stderr, "usage: %s [-r] name\n", Prog);
  149.     exit (2);
  150. }
  151.  
  152. /*
  153.  * update_groups - delete user from secondary group set
  154.  *
  155.  *    update_groups() takes the user name that was given and searches
  156.  *    the group files for membership in any group.
  157.  */
  158.  
  159. void
  160. update_groups ()
  161. {
  162.     int    i;
  163.     struct    group    *grp;
  164. #ifdef    SHADOWGRP
  165.     struct    sgrp    *sgrp;
  166. #endif
  167.  
  168.     /*
  169.      * Scan through the entire group file looking for the groups that
  170.      * the user is a member of.
  171.      */
  172.  
  173.     for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
  174.  
  175.         /*
  176.          * See if the user specified this group as one of their
  177.          * concurrent groups.
  178.          */
  179.  
  180.         for (i = 0;grp->gr_mem[i];i++)
  181.             if (strcmp (grp->gr_mem[i], user_name) == 0)
  182.                 break;
  183.  
  184.         if (grp->gr_mem[i] == (char *) 0)
  185.             continue;
  186.  
  187.         /* 
  188.          * Delete the username from the list of group members and
  189.          * update the group entry to reflect the change.
  190.          */
  191.  
  192.         grp->gr_mem = del_list (grp->gr_mem, user_name);
  193.         if (! gr_update (grp)) {
  194.             fprintf (stderr, "%s: error updating group entry\n",
  195.                 Prog);
  196.             exit (1);
  197.         }
  198.         /*
  199.          * Update the DBM group file with the new entry as well.
  200.          */
  201.  
  202. #ifdef    NDBM
  203.         if (! gr_dbm_update (grp)) {
  204.             fprintf (stderr, "%s: cannot update dbm group entry\n",
  205.                 Prog);
  206.             exit (1);
  207.         }
  208.         endgrent ();
  209. #endif    /* NDBM */
  210. #ifdef    USE_SYSLOG
  211.         syslog (LOG_INFO, "delete `%s' from group `%s'\n",
  212.             user_name, grp->gr_name);
  213. #endif
  214.     }
  215.  
  216. #ifdef    SHADOWGRP
  217.     /*
  218.      * Scan through the entire shadow group file looking for the groups
  219.      * that the user is a member of.  Both the administrative list and
  220.      * the ordinary membership list is checked.
  221.      */
  222.  
  223.     for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
  224.         int    group_changed = 0;
  225.  
  226.         /*
  227.          * See if the user specified this group as one of their
  228.          * concurrent groups.
  229.          */
  230.  
  231.         for (i = 0;sgrp->sg_mem[i];i++)
  232.             if (strcmp (sgrp->sg_mem[i], user_name) == 0)
  233.                 break;
  234.  
  235.         if (sgrp->sg_mem[i]) {
  236.             sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
  237.             group_changed = 1;
  238.         }
  239.         for (i = 0;sgrp->sg_adm[i];i++)
  240.             if (strcmp (sgrp->sg_adm[i], user_name) == 0)
  241.                 break;
  242.  
  243.         if (sgrp->sg_adm[i]) {
  244.             sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
  245.             group_changed = 1;
  246.         }
  247.         if (! group_changed)
  248.             continue;
  249.  
  250.         if (! sgr_update (sgrp)) {
  251.             fprintf (stderr, "%s: error updating group entry\n",
  252.                 Prog);
  253.             exit (1);
  254.         }
  255. #ifdef    NDBM
  256.         /*
  257.          * Update the DBM group file with the new entry as well.
  258.          */
  259.  
  260.         if (! sgr_dbm_update (sgrp)) {
  261.             fprintf (stderr, "%s: cannot update dbm group entry\n",
  262.                 Prog);
  263.             exit (1);
  264.         }
  265.         endsgent ();
  266. #endif
  267. #ifdef    USE_SYSLOG
  268.         syslog (LOG_INFO, "delete `%s' from shadow group `%s'\n",
  269.             user_name, sgrp->sg_name);
  270. #endif
  271.     }
  272. #endif
  273. }
  274.  
  275. /*
  276.  * close_files - close all of the files that were opened
  277.  *
  278.  *    close_files() closes all of the files that were opened for this
  279.  *    new user.  This causes any modified entries to be written out.
  280.  */
  281.  
  282. close_files ()
  283. {
  284.     if (! pw_close ()) {
  285.         fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
  286.         exit (1);
  287.     }
  288.     if (! spw_close ()) {
  289.         fprintf (stderr, "%s: cannot rewrite shadow password file\n",    
  290.             Prog);
  291.         exit (1);
  292.     }
  293.     if (! gr_close ()) {
  294.         fprintf (stderr, "%s: cannot rewrite group file\n",
  295.             Prog);
  296.         exit (10);
  297.     }
  298.     (void) gr_unlock ();
  299. #ifdef    SHADOWGRP
  300.     if (! sgr_close ()) {
  301.         fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  302.             Prog);
  303.         exit (10);
  304.     }
  305.     (void) sgr_unlock ();
  306. #endif
  307.     (void) spw_unlock ();
  308.     (void) pw_unlock ();
  309. }
  310.  
  311. /*
  312.  * open_files - lock and open the password files
  313.  *
  314.  *    open_files() opens the two password files.
  315.  */
  316.  
  317. open_files ()
  318. {
  319.     if (! pw_lock ()) {
  320.         fprintf (stderr, "%s: unable to lock password file\n", Prog);
  321.         exit (1);
  322.     }
  323.     if (! pw_open (O_RDWR)) {
  324.         fprintf (stderr, "%s: unable to open password file\n", Prog);
  325.         exit (1);
  326.     }
  327.     if (! spw_lock ()) {
  328.         fprintf (stderr, "%s: cannot lock shadow password file\n", Prog);
  329.         exit (1);
  330.     }
  331.     if (! spw_open (O_RDWR)) {
  332.         fprintf (stderr, "%s: cannot open shadow password file\n", Prog);
  333.         exit (1);
  334.     }
  335.     if (! gr_lock ()) {
  336.         fprintf (stderr, "%s: unable to lock group file\n", Prog);
  337.         exit (1);
  338.     }
  339.     if (! gr_open (O_RDWR)) {
  340.         fprintf (stderr, "%s: cannot open group file\n", Prog);
  341.         exit (1);
  342.     }
  343. #ifdef    SHADOWGRP
  344.     if (! sgr_lock ()) {
  345.         fprintf (stderr, "%s: unable to lock shadow group file\n", Prog);
  346.         exit (1);
  347.     }
  348.     if (! sgr_open (O_RDWR)) {
  349.         fprintf (stderr, "%s: cannot open shadow group file\n", Prog);
  350.         exit (1);
  351.     }
  352. #endif
  353. }
  354.  
  355. /*
  356.  * update_user - delete the user entries
  357.  *
  358.  *    update_user() deletes the password file entries for this user
  359.  *    and will update the group entries as required.
  360.  */
  361.  
  362. update_user ()
  363. {
  364.     struct    passwd    *pwd;
  365.  
  366.     if (! pw_remove (user_name))
  367.         fprintf (stderr, "%s: error deleting password entry\n", Prog);
  368.  
  369.     if (! spw_remove (user_name))
  370.         fprintf (stderr, "%s: error deleting shadow password entry\n",
  371.             Prog);
  372.  
  373. #if defined(DBM) || defined(NDBM)
  374.     if (access ("/etc/passwd.pag", 0) == 0) {
  375.         if ((pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd))
  376.             fprintf (stderr,
  377.                 "%s: error deleting password dbm entry\n",
  378.                 Prog);
  379.  
  380.         endpwent ();
  381.     }
  382.  
  383.     /*
  384.      * If the user's UID is a duplicate the duplicated entry needs
  385.      * to be updated so that a UID match can be found in the DBM
  386.      * files.
  387.      */
  388.  
  389.     for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
  390.         if (pwd->pw_uid == user_id) {
  391.             pw_dbm_update (pwd);
  392.             endpwent ();
  393.             break;
  394.         }
  395.     }
  396. #endif
  397. #ifdef    NDBM
  398.     if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_remove (user_name))
  399.         fprintf (stderr, "%s: error deleting shadow passwd dbm entry\n",
  400.             Prog);
  401.  
  402.     endspent ();
  403. #endif
  404. #ifdef    USE_SYSLOG
  405.     syslog (LOG_INFO, "delete user `%s'\n", user_name);
  406. #endif
  407. }
  408.  
  409. /*
  410.  * main - useradd command
  411.  */
  412.  
  413. main (argc, argv)
  414. int    argc;
  415. char    **argv;
  416. {
  417.     struct    passwd    *pwd;
  418.     int    arg;
  419.     int    errors = 0;
  420.     extern    int    optind;
  421.     extern    char    *optarg;
  422.  
  423.     /*
  424.      * Get my name so that I can use it to report errors.
  425.      */
  426.  
  427.     if (Prog = strrchr (argv[0], '/'))
  428.         Prog++;
  429.     else
  430.         Prog = argv[0];
  431.  
  432. #ifdef    USE_SYSLOG
  433.     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  434. #endif
  435.  
  436.     /*
  437.      * The open routines for the DBM files don't use read-write
  438.      * as the mode, so we have to clue them in.
  439.      */
  440.  
  441. #if defined(DBM) || defined(NDBM)
  442.     pw_dbm_mode = O_RDWR;
  443. #endif
  444. #ifdef    NDBM
  445.     sp_dbm_mode = O_RDWR;
  446.     gr_dbm_mode = O_RDWR;
  447. #ifdef    SHADOWGRP
  448.     sg_dbm_mode = O_RDWR;
  449. #endif
  450. #endif
  451.     while ((arg = getopt (argc, argv, "r")) != EOF)
  452.         if (arg != 'r')
  453.             usage ();
  454.         else
  455.             rflg++;
  456.     
  457.     if (optind == argc)
  458.         usage ();
  459.  
  460.     /*
  461.      * Start with a quick check to see if the user exists.
  462.      */
  463.  
  464.     strncpy (user_name, argv[argc - 1], BUFSIZ);
  465.  
  466.     if (! (pwd = getpwnam (user_name))) {
  467.         fprintf (stderr, "%s: user %s does not exist\n",
  468.             Prog, user_name);
  469.         exit (6);
  470.     }
  471.     user_id = pwd->pw_uid;
  472.     strcpy (user_home, pwd->pw_dir);
  473.  
  474.     /*
  475.      * Do the hard stuff - open the files, create the user entries,
  476.      * create the home directory, then close and update the files.
  477.      */
  478.  
  479.     open_files ();
  480.  
  481.     update_user ();
  482.     update_groups ();
  483.  
  484.     if (rflg) {
  485.         if (remove_tree (user_home) || rmdir (user_home))
  486.             errors++;
  487.     }
  488.     close_files ();
  489.     exit (errors ? 12:0);
  490.     /*NOTREACHED*/
  491. }
  492.